﻿Imports System.IO

Namespace Logging

    ''' <summary>
    ''' Provides simple logging functionality for a PowerSong database.
    ''' </summary>
    Public Class ActivityLog

        Private FDatabase As Database = Nothing

        Private FFiles As New Dictionary(Of String, FileStream)

        ''' <summary>
        ''' Adds the specified log entry to the activity log.
        ''' The entry is only added if logging is enabled by the database's settings.
        ''' </summary>
        ''' <param name="itemSort">The type of log entry to record.</param>
        ''' <param name="id">The ID of the item in question.</param>
        ''' <param name="time">The time of the action.</param>
        ''' <param name="action">The action performed.</param>
        Public Sub Add(ByVal itemSort As LogEntry.ItemType, _
                       ByVal id As Guid, _
                       ByVal time As Date, _
                       ByVal action As LogEntry.Action)

            ' Only do this if logging is enabled
            If FDatabase.Settings.EnableLogging Then

                ' Ensure the file handle exists
                Dim File As FileStream = GetFileHandle(time.Year, time.Month)

                ' Add to the file
                File.Seek(0, SeekOrigin.End)
                File.WriteByte(DirectCast(itemSort, Byte))
                File.Write(id.ToByteArray, 0, 16)
                File.WriteByte(CByte(time.Day))
                File.WriteByte(CByte(time.Hour))
                File.WriteByte(CByte(time.Minute))
                File.WriteByte(CByte(time.Second))
                File.WriteByte(DirectCast(action, Byte))

            End If

        End Sub

        ''' <summary>
        ''' Determines the number of records available for the given year and month.
        ''' </summary>
        ''' <param name="year">The year.</param>
        ''' <param name="month">The month.</param>
        ''' <returns>The number of records for the given year and month.</returns>
        Public Function RecordCount(ByVal year As Integer, ByVal month As Integer) As Integer

            If LogFileExists(year, month) Then
                Dim File As FileStream = GetFileHandle(year, month)
                Return File.Length / 22
            Else
                Return 0
            End If

        End Function

        ''' <summary>
        ''' Gets the requested record, based on its date and record index.
        ''' A log file must exist for the given year and month before records can be retrieved.
        ''' </summary>
        ''' <param name="year">The year.</param>
        ''' <param name="month">The month.</param>
        ''' <param name="recordIndex">Index of the record to retrieve in the given year and month.</param>
        ''' <returns>The requested record.</returns>
        Public Function GetRecord(ByVal year As Integer, _
                                  ByVal month As Integer, _
                                  ByVal recordIndex As Integer) As LogEntry

            ' Check that the log file exists
            If Not LogFileExists(year, month) Then Throw New Exception("A log file for " + month.ToString + "/" + year.ToString + " does not exist.")

            ' Get the record data
            Dim File As FileStream = FFiles(GetFileName(year, month))
            File.Seek(22 * recordIndex, SeekOrigin.Begin)
            Dim ItemSort As LogEntry.ItemType = File.ReadByte
            Dim ItemID(15) As Byte
            File.Read(ItemID, 0, 16)
            Dim Day As Byte = CByte(File.ReadByte)
            Dim Hour As Byte = CByte(File.ReadByte)
            Dim Minute As Byte = CByte(File.ReadByte)
            Dim Second As Byte = CByte(File.ReadByte)
            Dim Time As New DateTime(year, month, Day, Hour, Minute, Second)
            Dim Action As LogEntry.Action = File.ReadByte

            ' Return the result
            Return New LogEntry(ItemSort, New Guid(ItemID), Time, Action)

        End Function

        ''' <summary>
        ''' Determines whether or not a log file exists for the given year and month.
        ''' </summary>
        ''' <param name="year">The year.</param>
        ''' <param name="month">The month.</param>
        ''' <returns>True, if the log file exists. False otherwise.</returns>
        Public Function LogFileExists(ByVal year As Integer, ByVal month As Integer) As Boolean

            Return File.Exists(FDatabase.Location + "\" + GetFileName(year, month))

        End Function

        ''' <summary>
        ''' Gets the name of the log file for the given date.
        ''' </summary>
        ''' <param name="year">The year.</param>
        ''' <param name="month">The month.</param>
        ''' <returns>The file name of the log file that would or does exist for the given date.</returns>
        Private Function GetFileName(ByVal year As Integer, ByVal month As Integer) As String

            Dim YearString As String = year.ToString
            Dim MonthString As String = month.ToString.PadLeft(2, "0")
            Return YearString + "_" + MonthString + ".Log"

        End Function

        Private Function GetFileHandle(ByVal year As Integer, ByVal month As Integer) As FileStream

            Dim FileName As String = GetFileName(year, month)
            If Not FFiles.ContainsKey(FileName) Then
                FFiles.Add(FileName, New FileStream(FDatabase.Location + "\" + FileName, FileMode.OpenOrCreate))
            End If
            Return FFiles(FileName)

        End Function

        Public Sub CloseAllFileHandles()
            For Each File As KeyValuePair(Of String, FileStream) In FFiles
                File.Value.Close()
            Next
            FFiles.Clear()
        End Sub

        Friend Sub New(ByVal database As Database)
            FDatabase = database
        End Sub

    End Class

End Namespace